// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_H_
#define CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/reload_type.h"
#include "content/public/browser/restore_type.h"
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/site_instance.h"
#include "content/public/common/referrer.h"
#include "content/public/common/resource_request_body.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"

namespace base {

class RefCountedString;

} // namespace base

namespace content {

class BrowserContext;
class NavigationEntry;
class WebContents;

// A NavigationController maintains the back-forward list for a WebContents and
// manages all navigation within that list.
//
// Each NavigationController belongs to one WebContents; each WebContents has
// exactly one NavigationController.
class NavigationController {
public:
    // Load type used in LoadURLParams.
    //
    // A Java counterpart will be generated for this enum.
    // GENERATED_JAVA_ENUM_PACKAGE: (
    //   org.chromium.content_public.browser.navigation_controller)
    // GENERATED_JAVA_PREFIX_TO_STRIP: LOAD_TYPE_
    enum LoadURLType {
        // For loads that do not fall into any types below.
        LOAD_TYPE_DEFAULT,

        // An http post load request.  The post data is passed in |post_data|.
        LOAD_TYPE_HTTP_POST,

        // Loads a 'data:' scheme URL with specified base URL and a history entry
        // URL. This is only safe to be used for browser-initiated data: URL
        // navigations, since it shows arbitrary content as if it comes from
        // |virtual_url_for_data_url|.
        LOAD_TYPE_DATA

        // Adding new LoadURLType? Also update LoadUrlParams.java static constants.
    };

    // User agent override type used in LoadURLParams.
    //
    // A Java counterpart will be generated for this enum.
    // GENERATED_JAVA_ENUM_PACKAGE: (
    //   org.chromium.content_public.browser.navigation_controller)
    // GENERATED_JAVA_PREFIX_TO_STRIP: UA_OVERRIDE_
    enum UserAgentOverrideOption {
        // Use the override value from the previous NavigationEntry in the
        // NavigationController.
        UA_OVERRIDE_INHERIT,

        // Use the default user agent.
        UA_OVERRIDE_FALSE,

        // Use the user agent override, if it's available.
        UA_OVERRIDE_TRUE

        // Adding new UserAgentOverrideOption? Also update LoadUrlParams.java
        // static constants.
    };

    // Creates a navigation entry and translates the virtual url to a real one.
    // This is a general call; prefer LoadURL[FromRenderer]/TransferURL below.
    // Extra headers are separated by \n.
    CONTENT_EXPORT static std::unique_ptr<NavigationEntry> CreateNavigationEntry(
        const GURL& url,
        const Referrer& referrer,
        ui::PageTransition transition,
        bool is_renderer_initiated,
        const std::string& extra_headers,
        BrowserContext* browser_context);

    // Extra optional parameters for LoadURLWithParams.
    struct CONTENT_EXPORT LoadURLParams {
        // The url to load. This field is required.
        GURL url;

        // SiteInstance of the frame that initiated the navigation or null if we
        // don't know it.
        scoped_refptr<SiteInstance> source_site_instance;

        // See LoadURLType comments above.
        LoadURLType load_type;

        // PageTransition for this load. See PageTransition for details.
        // Note the default value in constructor below.
        ui::PageTransition transition_type;

        // The FrameTreeNode ID for the frame to navigate, or -1 for the main frame.
        int frame_tree_node_id;

        // Referrer for this load. Empty if none.
        Referrer referrer;

        // Any redirect URLs that occurred for this navigation before |url|.
        // Defaults to an empty vector.
        std::vector<GURL> redirect_chain;

        // Extra headers for this load, separated by \n.
        std::string extra_headers;

        // True for renderer-initiated navigations. This is
        // important for tracking whether to display pending URLs.
        bool is_renderer_initiated;

        // User agent override for this load. See comments in
        // UserAgentOverrideOption definition.
        UserAgentOverrideOption override_user_agent;

        // Marks the new navigation as being transferred from one RVH to another.
        // In this case the browser can recycle the old request once the new
        // renderer wants to navigate. Identifies the request ID of the old request.
        GlobalRequestID transferred_global_request_id;

        // Used in LOAD_TYPE_DATA loads only. Used for specifying a base URL
        // for pages loaded via data URLs.
        GURL base_url_for_data_url;

        // Used in LOAD_TYPE_DATA loads only. URL displayed to the user for
        // data loads.
        GURL virtual_url_for_data_url;

#if defined(OS_ANDROID)
        // Used in LOAD_TYPE_DATA loads only. The real data URI is represented
        // as a string to circumvent the restriction on GURL size. This is only
        // needed to pass URLs that exceed the IPC limit (kMaxURLChars). Short
        // data: URLs can be passed in the |url| field.
        scoped_refptr<base::RefCountedString> data_url_as_string;
#endif

        // Used in LOAD_TYPE_HTTP_POST loads only. Carries the post data of the
        // load.  Ownership is transferred to NavigationController after
        // LoadURLWithParams call.
        scoped_refptr<ResourceRequestBody> post_data;

        // True if this URL should be able to access local resources.
        bool can_load_local_resources;

        // Indicates whether this navigation should replace the current
        // navigation entry.
        bool should_replace_current_entry;

        // Used to specify which frame to navigate. If empty, the main frame is
        // navigated. This is currently only used in tests.
        std::string frame_name;

#if defined(OS_ANDROID)
        // On Android, for a load triggered by an intent, the time Chrome received
        // the original intent that prompted the load (in milliseconds active time
        // since boot).
        int64_t intent_received_timestamp;

        // When Chrome launches the intent chooser, user can select Chrome itself to
        // open the intent. In this case, we should carry over the user gesture.
        bool has_user_gesture;
#endif

        // Indicates that during this navigation, the session history should be
        // cleared such that the resulting page is the first and only entry of the
        // session history.
        //
        // The clearing is done asynchronously, and completes when this navigation
        // commits.
        bool should_clear_history_list;

        // Indicates whether or not this navigation was initiated via context menu.
        bool started_from_context_menu;

        explicit LoadURLParams(const GURL& url);
        ~LoadURLParams();

        // Allows copying of LoadURLParams struct.
        LoadURLParams(const LoadURLParams& other);
        LoadURLParams& operator=(const LoadURLParams& other);
    };

    // Disables checking for a repost and prompting the user. This is used during
    // testing.
    CONTENT_EXPORT static void DisablePromptOnRepost();

    virtual ~NavigationController() { }

    // Returns the web contents associated with this controller. It can never be
    // nullptr.
    virtual WebContents* GetWebContents() const = 0;

    // Get the browser context for this controller. It can never be nullptr.
    virtual BrowserContext* GetBrowserContext() const = 0;

    // Initializes this NavigationController with the given saved navigations,
    // using |selected_navigation| as the currently loaded entry. Before this call
    // the controller should be unused (there should be no current entry). |type|
    // indicates where the restor comes from. This takes ownership of the
    // NavigationEntrys in |entries| and clears it out. This is used for session
    // restore.
    virtual void Restore(
        int selected_navigation,
        RestoreType type,
        std::vector<std::unique_ptr<NavigationEntry>>* entries)
        = 0;

    // Entries -------------------------------------------------------------------

    // There are two basic states for entries: pending and committed. When an
    // entry is navigated to, a request is sent to the server. While that request
    // has not been responded to, the NavigationEntry is pending. Once data is
    // received for that entry, that NavigationEntry is committed.

    // A transient entry is an entry that, when the user navigates away, is
    // removed and discarded rather than being added to the back-forward list.
    // Transient entries are useful for interstitial pages and the like.

    // Active entry --------------------------------------------------------------

    // THIS IS DEPRECATED. DO NOT USE. Use GetVisibleEntry instead.
    // See http://crbug.com/273710.
    //
    // Returns the active entry, which is the transient entry if any, the pending
    // entry if a navigation is in progress or the last committed entry otherwise.
    // NOTE: This can be nullptr!!
    virtual NavigationEntry* GetActiveEntry() const = 0;

    // Returns the entry that should be displayed to the user in the address bar.
    // This is the transient entry if any, the pending entry if a navigation is
    // in progress *and* is safe to display to the user (see below), or the last
    // committed entry otherwise.
    // NOTE: This can be nullptr if no entry has committed!
    //
    // A pending entry is safe to display if it started in the browser process or
    // if it's a renderer-initiated navigation in a new tab which hasn't been
    // accessed by another tab.  (If it has been accessed, it risks a URL spoof.)
    virtual NavigationEntry* GetVisibleEntry() const = 0;

    // Returns the index from which we would go back/forward or reload.  This is
    // the last_committed_entry_index_ if pending_entry_index_ is -1.  Otherwise,
    // it is the pending_entry_index_.
    virtual int GetCurrentEntryIndex() const = 0;

    // Returns the last committed entry, which may be null if there are no
    // committed entries.
    virtual NavigationEntry* GetLastCommittedEntry() const = 0;

    // Returns the index of the last committed entry.
    virtual int GetLastCommittedEntryIndex() const = 0;

    // Returns true if the source for the current entry can be viewed.
    virtual bool CanViewSource() const = 0;

    // Navigation list -----------------------------------------------------------

    // Returns the number of entries in the NavigationController, excluding
    // the pending entry if there is one, but including the transient entry if
    // any.
    virtual int GetEntryCount() const = 0;

    virtual NavigationEntry* GetEntryAtIndex(int index) const = 0;

    // Returns the entry at the specified offset from current.  Returns nullptr
    // if out of bounds.
    virtual NavigationEntry* GetEntryAtOffset(int offset) const = 0;

    // Pending entry -------------------------------------------------------------

    // Discards the pending and transient entries if any.
    virtual void DiscardNonCommittedEntries() = 0;

    // Returns the pending entry corresponding to the navigation that is
    // currently in progress, or null if there is none.
    virtual NavigationEntry* GetPendingEntry() const = 0;

    // Returns the index of the pending entry or -1 if the pending entry
    // corresponds to a new navigation (created via LoadURL).
    virtual int GetPendingEntryIndex() const = 0;

    // Transient entry -----------------------------------------------------------

    // Returns the transient entry if any. This is an entry which is removed and
    // discarded if any navigation occurs. Note that the returned entry is owned
    // by the navigation controller and may be deleted at any time.
    virtual NavigationEntry* GetTransientEntry() const = 0;

    // Adds an entry that is returned by GetActiveEntry(). The entry is
    // transient: any navigation causes it to be removed and discarded.  The
    // NavigationController becomes the owner of |entry| and deletes it when
    // it discards it. This is useful with interstitial pages that need to be
    // represented as an entry, but should go away when the user navigates away
    // from them.
    // Note that adding a transient entry does not change the active contents.
    virtual void SetTransientEntry(std::unique_ptr<NavigationEntry> entry) = 0;

    // New navigations -----------------------------------------------------------

    // Loads the specified URL, specifying extra http headers to add to the
    // request.  Extra headers are separated by \n.
    virtual void LoadURL(const GURL& url,
        const Referrer& referrer,
        ui::PageTransition type,
        const std::string& extra_headers)
        = 0;

    // More general version of LoadURL. See comments in LoadURLParams for
    // using |params|.
    virtual void LoadURLWithParams(const LoadURLParams& params) = 0;

    // Loads the current page if this NavigationController was restored from
    // history and the current page has not loaded yet or if the load was
    // explicitly requested using SetNeedsReload().
    virtual void LoadIfNecessary() = 0;

    // Renavigation --------------------------------------------------------------

    // Navigation relative to the "current entry"
    virtual bool CanGoBack() const = 0;
    virtual bool CanGoForward() const = 0;
    virtual bool CanGoToOffset(int offset) const = 0;
    virtual void GoBack() = 0;
    virtual void GoForward() = 0;

    // Navigates to the specified absolute index.
    virtual void GoToIndex(int index) = 0;

    // Navigates to the specified offset from the "current entry". Does nothing if
    // the offset is out of bounds.
    virtual void GoToOffset(int offset) = 0;

    // Reloads the current entry under the specified ReloadType.  If
    // |check_for_repost| is true and the current entry has POST data the user is
    // prompted to see if they really want to reload the page.  In nearly all
    // cases pass in true in production code, but would do false for testing, or
    // in cases where no user interface is available for prompting.  If a
    // transient entry is showing, initiates a new navigation to its URL.
    virtual void Reload(ReloadType reload_type, bool check_for_repost) = 0;

    // Removing of entries -------------------------------------------------------

    // Removes the entry at the specified |index|.  If the index is the last
    // committed index or the pending entry, this does nothing and returns false.
    // Otherwise this call discards any transient or pending entries.
    virtual bool RemoveEntryAtIndex(int index) = 0;

    // Random --------------------------------------------------------------------

    // Session storage depends on dom_storage that depends on blink::WebString.
    // Returns all the SessionStorageNamespace objects that this
    // NavigationController knows about, the map key is a StoragePartition id.
    virtual const SessionStorageNamespaceMap&
    GetSessionStorageNamespaceMap() const = 0;

    // TODO(ajwong): Remove this once prerendering, instant, and session restore
    // are migrated.
    virtual SessionStorageNamespace* GetDefaultSessionStorageNamespace() = 0;

    // Returns true if a reload happens when activated (SetActive(true) is
    // invoked). This is true for session/tab restore, cloned tabs and tabs that
    // requested a reload (using SetNeedsReload()) after their renderer was
    // killed.
    virtual bool NeedsReload() const = 0;

    // Request a reload to happen when activated. This can be used when a renderer
    // backing a background tab is killed by the system on Android or ChromeOS.
    virtual void SetNeedsReload() = 0;

    // Cancels a repost that brought up a warning.
    virtual void CancelPendingReload() = 0;
    // Continues a repost that brought up a warning.
    virtual void ContinuePendingReload() = 0;

    // Returns true if this is a newly created tab or a cloned tab, which has not
    // yet committed a real page. Returns false after the initial navigation has
    // committed.
    virtual bool IsInitialNavigation() const = 0;

    // Returns true if this is a newly created tab (not a clone) that has not yet
    // committed a real page.
    virtual bool IsInitialBlankNavigation() const = 0;

    // Broadcasts the NOTIFICATION_NAV_ENTRY_CHANGED notification for the given
    // entry. This will keep things in sync like the saved session.
    virtual void NotifyEntryChanged(const NavigationEntry* entry) = 0;

    // Copies the navigation state from the given controller to this one. This
    // one should be empty (just created).
    virtual void CopyStateFrom(const NavigationController& source) = 0;

    // A variant of CopyStateFrom. Removes all entries from this except the last
    // committed entry, and inserts all entries from |source| before and including
    // its last committed entry. For example:
    // source: A B *C* D
    // this:   E F *G*
    // result: A B C *G*
    // If there is a pending entry after *G* in |this|, it is also preserved.
    // If |replace_entry| is true, the current entry in |source| is replaced. So
    // the result above would be A B *G*.
    // This ignores any pending or transient entries in |source|.  Callers must
    // ensure that |CanPruneAllButLastCommitted| returns true before calling this,
    // or it will crash.
    virtual void CopyStateFromAndPrune(NavigationController* source,
        bool replace_entry)
        = 0;

    // Returns whether it is safe to call PruneAllButLastCommitted or
    // CopyStateFromAndPrune.  There must be a last committed entry, no transient
    // entry, and if there is a pending entry, it must be new and not an existing
    // entry.
    //
    // If there were no last committed entry, the pending entry might not commit,
    // leaving us with a blank page.  This is unsafe when used with
    // |CopyStateFromAndPrune|, which would show an existing entry above the blank
    // page.
    // If there were a transient entry, we would not want to prune the other
    // entries, which the transient entry could be referring to.
    // If there were an existing pending entry, we could not prune the last
    // committed entry, in case it did not commit.  That would leave us with no
    // sensible place to put the pending entry when it did commit, after all other
    // entries are pruned.  For example, it could be going back several entries.
    // (New pending entries are safe, because they can always commit to the end.)
    virtual bool CanPruneAllButLastCommitted() = 0;

    // Removes all the entries except the last committed entry. If there is a new
    // pending navigation it is preserved.  Callers must ensure
    // |CanPruneAllButLastCommitted| returns true before calling this, or it will
    // crash.
    virtual void PruneAllButLastCommitted() = 0;

    // Clears all screenshots associated with navigation entries in this
    // controller. Useful to reduce memory consumption in low-memory situations.
    virtual void ClearAllScreenshots() = 0;

private:
    // This interface should only be implemented inside content.
    friend class NavigationControllerImpl;
    NavigationController() { }
};

} // namespace content

#endif // CONTENT_PUBLIC_BROWSER_NAVIGATION_CONTROLLER_H_
